<template>
	<view :id="elId" class="v-tabs">
		<scroll-view
			id="scrollContainer"
			:class="{ 'is-center': tabs?.length <= 4 }"
			:scroll-x="scroll"
			:scroll-left="scroll ? scrollLeft : 0"
			:scroll-with-animation="scroll"
			:style="{ position: fixed ? 'fixed' : 'relative', zIndex: 1993 }"
		>
			<view
				class="v-tabs__container"
				:style="{
					display: scroll ? 'inline-flex' : 'flex',
					whiteSpace: scroll ? 'nowrap' : 'normal',
					background: bgColor,
					height,
					padding,
				}"
			>
				<view
					class="v-tabs__container-item"
					:class="current == i ? 'v-tabs__container-active' : ''"
					v-for="(v, i) in tabs"
					:key="i"
					:style="{
						color: current == i ? activeColor : color,
						fontSize: current == i ? activeFontSize : fontSize,
						fontWeight: bold && current == i ? '' : '',
						justifyContent: !scroll ? 'center' : '',
						flex: scroll ? '' : 1,
						padding: paddingItem,
					}"
					@click="onChange(i)"
				>
					{{ field ? v[field] : v }}
				</view>
				<view
					v-if="!pills"
					:class="['v-tabs__container-line', { animation: lineAnimation }]"
					:style="{
						background: lineColor,
						width: lineWidth + 'px',
						height: lineHeight,
						borderRadius: lineRadius,
						left: lineLeft + 'px',
						transform: `translateX(-${lineWidth / 2}px)`,
					}"
				></view>
				<view
					v-else
					:class="['v-tabs__container-pills', { animation: lineAnimation }]"
					:style="{
						background: pillsColor,
						borderRadius: pillsBorderRadius,
						left: pillsLeft + 'px',
						width: currentWidth + 'px',
						height,
					}"
				></view>
			</view>
		</scroll-view>
		<view
			class="v-tabs__placeholder"
			:style="{
				height: fixed ? height : '0',
				padding,
			}"
		></view>
	</view>
</template>

<script setup>
	import { ref, watch, nextTick, onMounted } from 'vue';
	import { tabsProps } from './props';

	const props = defineProps(tabsProps);
	const emit = defineEmits(['update:modelValue']);

	const elId = ref('');
	const lineWidth = ref(30);
	const currentWidth = ref(0); // 当前选项的宽度
	const lineLeft = ref(0); // 滑块距离左侧的位置
	const pillsLeft = ref(0); // 胶囊距离左侧的位置
	const scrollLeft = ref(0); // 距离左边的位置
	const current = ref(0); // 当前选中项
	let containerWidth = 0; // 容器的宽度

	// 监听
	watch(
		() => props.modelValue,
		(newVal) => {
			current.value = newVal;
			nextTick(() => {
				getTabItemWidth();
			});
		}
	);

	watch(
		() => props.tabs,
		(newVal) => {
			current.value = newVal;
			nextTick(() => {
				getTabItemWidth();
			});
		}
	);

	// 切换事件
	const onChange = (index) => {
		if (current.value !== index) {
			emit('update:modelValue', index);
		}
	};

	// 产生随机字符串
	const randomString = (len = 32) => {
		let $chars =
			'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
		let maxPos = $chars.length;
		let pwd = '';
		for (let i = 0; i < len; i++) {
			pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
		}
		return pwd;
	};

	// 获取左移动位置
	const getTabItemWidth = () => {
		let query = uni
			.createSelectorQuery()
			// #ifndef MP-ALIPAY
			.in(this);
		// #endif

		// 获取容器的宽度
		query
			.select(`#scrollContainer`)
			.boundingClientRect((data) => {
				if (!containerWidth && data) {
					containerWidth = data.width;
				}
			})
			.exec();

		// 获取所有的 tab-item 的宽度
		query
			.selectAll('.v-tabs__container-item')
			.boundingClientRect((data) => {
				if (!data) {
					return;
				}
				let lineLf = 0;
				let currentWid = 0;
				if (data) {
					for (let i = 0; i < data.length; i++) {
						if (i < current.value) {
							lineLf += data[i].width;
						} else if (i == current.value) {
							currentWid = data[i].width;
						} else {
							break;
						}
					}
				}

				// 当前滑块的宽度
				currentWidth.value = currentWid;
				// 缩放后的滑块宽度
				lineWidth.value = currentWid * props.lineScale * 1;
				// 滑块作移动的位置
				lineLeft.value = lineLf + currentWid / 2;
				// 胶囊距离左侧的位置
				pillsLeft.value = lineLf;
				// 计算滚动的距离左侧的位置
				if (props.scroll) {
					scrollLeft.value = lineLeft.value - containerWidth / 2;
				}
			})
			.exec();
	};

	onMounted(() => {
		elId.value = 'xfjpeter_' + randomString();

		nextTick(() => {
			getTabItemWidth();
		});
	});
</script>

<style lang="scss" scoped>
	.v-tabs {
		width: 100%;
		box-sizing: border-box;
		overflow: hidden;

		::-webkit-scrollbar {
			display: none;
		}

		.is-center {
			:deep(.uni-scroll-view-content) {
				display: flex;
				justify-content: center;
			}
		}

		&__container {
			// min-width: 100%;
			position: relative;
			display: inline-flex;
			align-items: center;
			white-space: nowrap;
			overflow: hidden;

			&-item {
				display: flex;
				align-items: center;
				height: 100%;
				position: relative;
				z-index: 10;
				// padding: 0 11px;
				transition: all 0.2s;
				white-space: nowrap;
			}

			&-line {
				position: absolute;
				bottom: 0;
			}

			&-pills {
				position: absolute;
				z-index: 9;
			}
			&-line,
			&-pills {
				&.animation {
					transition: all 0.2s linear;
				}
			}

			&-active {
				&:before {
					content: '';
					position: absolute;
					bottom: 0;
					left: 50%;
					transform: translateX(-50%);
					background-color: #f74e51;
					border-radius: 22rpx;
					width: 60rpx;
					height: 8rpx;
				}
			}
		}
	}
</style>
